package com.antoco.controlcenter.model.video.rxjava;

import com.antoco.controlcenter.base.Constants;
import com.antoco.controlcenter.comm.RobotMoveState;
import com.antoco.controlcenter.comm.message.NciMessage;
import com.antoco.controlcenter.comm.message.RobotMessageBase;
import com.antoco.controlcenter.iface.IMoveEventListener;
import com.antoco.controlcenter.model.video.iface.IMoveSpeedListener;
import com.antoco.controlcenter.utils.BytesUtils;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;

import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Consumer;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.schedulers.Schedulers;

public class MoveRobotEventing {
    private static MoveRobotEventing instance = null;
    private ConcurrentMap<String, String> instructMap = new ConcurrentHashMap<>(); //指令表
    private ConcurrentLinkedQueue<NciMessage> nciQueue = new ConcurrentLinkedQueue<>(); //NCI指令队列
    private IMoveEventListener moveEventListener;
    private CompositeDisposable mCompositeDisposable;
    private int robotGear;
    private IMoveSpeedListener iMoveSpeedListener;

    /**
     * 私有构造
     */
    private MoveRobotEventing() {
        mCompositeDisposable = new CompositeDisposable();
    }

    /**
     * 单例实例
     *
     * @return
     */
    public static MoveRobotEventing getInstance() {
        if (instance == null) {
            synchronized (MoveRobotEventing.class) {
                if (instance == null) {
                    instance = new MoveRobotEventing();
                }
            }
        }
        return instance;
    }

    public void setiMoveSpeedListener(IMoveSpeedListener iMoveSpeedListener) {
        this.iMoveSpeedListener = iMoveSpeedListener;
    }

    public void setRobotGear(int robotGear) {
        this.robotGear = robotGear;
    }

    public void setInstructMap(ConcurrentMap<String, String> instructMap) {
        this.instructMap = instructMap;
    }

    public void setNciQueue(ConcurrentLinkedQueue<NciMessage> nciQueue) {
        this.nciQueue = nciQueue;
    }

    public void setMoveEventListener(IMoveEventListener iMoveEventListener) {
        moveEventListener = iMoveEventListener;
    }

    public NciMessage getInstructNciMessage(String key) {
        if (null == instructMap) {
            return null;
        }
        if (instructMap.containsKey(key)) {
            return new NciMessage(BytesUtils.hexStringToByteArray(this.instructMap.get(key).replaceAll(" ", "")));
        }
        return null;
    }

    private void startMoveRunable() {
        RobotMessageBase frame = new RobotMessageBase(12);
        if (null != iMoveSpeedListener) {
            iMoveSpeedListener.moveSpeed();
        }
        if (Constants.MOVESTATE == RobotMoveState.FORWARD) {
            NciMessage nci = getInstructNciMessage("ROBOT_MOVE");
            if (nci != null) {
                nci.SetData(robotGear);
                frame.AddNci(nci);
            }
        }
        if (Constants.MOVESTATE == RobotMoveState.BACKWARD) {
            NciMessage nci = getInstructNciMessage("ROBOT_MOVE");
            if (nci != null) {
                nci.SetData(-robotGear);
                frame.AddNci(nci);
            }
        }
        if (Constants.MOVESTATE == RobotMoveState.LEFT) {
            NciMessage nci = getInstructNciMessage("ROBOT_ROTATE");
            if (nci != null) {
                nci.SetData(robotGear);
                frame.AddNci(nci);
            }
        }
        if (Constants.MOVESTATE == RobotMoveState.RIGHT) {
            NciMessage nci = getInstructNciMessage("ROBOT_ROTATE");
            if (nci != null) {
                nci.SetData(-robotGear);
                frame.AddNci(nci);
            }
        }
        if (Constants.MOVESTATE == RobotMoveState.STOP) {
            NciMessage nci = getInstructNciMessage("ROBOT_MOVE");
            if (nci != null) {
                nci.SetData(0);
                frame.AddNci(nci);
            }
        }

        for (int i = 0; i < Math.min(4, nciQueue.size()); i++) {
            frame.AddNci(nciQueue.poll());
        }
        if (null != moveEventListener) {
            moveEventListener.onMoveChange(frame.GetByteArray());
        }
    }


    public void startPatchObservable() {
        Observable<Long> observable = Observable.interval(0, 550, TimeUnit.MILLISECONDS).doOnNext(new Consumer<Long>() {

            @Override
            public void accept(Long aLong) {
                startMoveRunable();
            }

        });
        DisposableObserver<Long> disposableObserver = getDisposableObserver();
        observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(disposableObserver);
        mCompositeDisposable.add(disposableObserver);
    }

    private DisposableObserver<Long> getDisposableObserver() {

        return new DisposableObserver<Long>() {

            @Override
            public void onNext(Long aLong) {
            }

            @Override
            public void onError(Throwable throwable) {
            }

            @Override
            public void onComplete() {
            }
        };
    }


    public void clear() {
        if (null == mCompositeDisposable) {
            return;
        }
        mCompositeDisposable.clear();
    }
}
